Se hará uso de los siguientes Paquetes, Módulos y Funciones
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
from predictPy import Analisis_Predictivo
from sklearn.preprocessing import StandardScaler
from sklearn.svm import SVC
import warnings
warnings.filterwarnings("ignore")Lectura de datos
datos = pd.read_csv('../datos/iris.csv',delimiter = ';',decimal = ".")
print(datos.shape)(150, 5)
print(datos.head()) s.largo s.ancho p.largo p.ancho tipo
0 5.1 3.5 1.4 0.2 setosa
1 4.9 3.0 1.4 0.2 setosa
2 4.7 3.2 1.3 0.2 setosa
3 4.6 3.1 1.5 0.2 setosa
4 5.0 3.6 1.4 0.2 setosa
print(datos.info())<class 'pandas.core.frame.DataFrame'>
RangeIndex: 150 entries, 0 to 149
Data columns (total 5 columns):
# Column Non-Null Count Dtype
--- ------ -------------- -----
0 s.largo 150 non-null float64
1 s.ancho 150 non-null float64
2 p.largo 150 non-null float64
3 p.ancho 150 non-null float64
4 tipo 150 non-null object
dtypes: float64(4), object(1)
memory usage: 6.0+ KB
None
analisis_Iris = Analisis_Predictivo(datos, predecir="tipo")analisis_Iris.distribucion_variable_predecir()
plt.show()Construcción de modelo
instancia_svm = SVC(kernel="rbf")
analisis_Iris = Analisis_Predictivo(datos,predecir= "tipo",modelo=instancia_svm, train_size= 0.7)Evaluación del modelo
resultados = analisis_Iris.fit_predict_resultados()
Matriz de Confusión:
[[15 0 0]
[ 0 9 1]
[ 0 0 20]]
Precisión Global:
0.9777777777777777
Error Global:
0.022222222222222254
Precisión por categoría:
setosa versicolor virginica
0 1.0 0.9 1.0
Construcción de modelo
# Tenemos disponibles los núcleos linear, poly, rbf, sigmoid, precomputed. Por defecto se utiliza rbf
# Si utilizamos poly podemos también indicar el grado del polinomio, esto mediante el parámetro degree. Por defecto degree = 3
# El parámetro C indica la fuerza de la regularización.
instancia_svm = SVC(kernel="poly", degree = 3, C = 20)
analisis_Iris = Analisis_Predictivo(datos,predecir= "tipo",modelo=instancia_svm, train_size= 0.7)Evaluación del modelo
resultados = analisis_Iris.fit_predict_resultados()
Matriz de Confusión:
[[18 0 0]
[ 0 12 4]
[ 0 1 10]]
Precisión Global:
0.8888888888888888
Error Global:
0.11111111111111116
Precisión por categoría:
setosa versicolor virginica
0 1.0 0.75 0.909091
datos = pd.read_csv('../datos/MuestraCredito5000V2.csv', delimiter = ';', decimal = ".", header = 0)
print(datos.shape)(5000, 6)
print(datos.info())<class 'pandas.core.frame.DataFrame'>
RangeIndex: 5000 entries, 0 to 4999
Data columns (total 6 columns):
# Column Non-Null Count Dtype
--- ------ -------------- -----
0 MontoCredito 5000 non-null int64
1 IngresoNeto 5000 non-null int64
2 CoefCreditoAvaluo 5000 non-null int64
3 MontoCuota 5000 non-null object
4 GradoAcademico 5000 non-null object
5 BuenPagador 5000 non-null object
dtypes: int64(3), object(3)
memory usage: 234.5+ KB
None
Preparación de datos
# Convierte las variables a categórica
datos['IngresoNeto'] = datos['IngresoNeto'].astype('category')
datos['MontoCuota'] = datos['MontoCuota'].astype('category')
datos['GradoAcademico'] = datos['GradoAcademico'].astype('category')
#Convertimos a Dummy algunas de las variables predictoras
datos = pd.get_dummies(datos, columns=["IngresoNeto", "MontoCuota", "GradoAcademico"])
datos.head() MontoCredito ... GradoAcademico_Licenciatura
0 14327 ... 0
1 111404 ... 0
2 21128 ... 0
3 15426 ... 0
4 10351 ... 0
[5 rows x 11 columns]
analisis_Credito = Analisis_Predictivo(datos, predecir="BuenPagador")
analisis_Credito.distribucion_variable_predecir()
plt.show()Construcción de modelo
instancia_svm = SVC(kernel="linear", C = 20)
analisis_Credito = Analisis_Predictivo(datos,predecir= "BuenPagador",modelo=instancia_svm, train_size= 0.75)Evaluación del modelo
resultados = analisis_Credito.fit_predict_resultados()
Matriz de Confusión:
[[ 0 167]
[ 0 1083]]
Precisión Global:
0.8664
Error Global:
0.13360000000000005
Precisión por categoría:
No Si
0 0.0 1.0
RBF
instancia_svm = SVC(kernel="rbf", C = 15)
analisis_Credito = Analisis_Predictivo(datos,predecir= "BuenPagador",modelo=instancia_svm, train_size= 0.75)
resultados = analisis_Credito.fit_predict_resultados()
Matriz de Confusión:
[[ 125 47]
[ 20 1058]]
Precisión Global:
0.9464
Error Global:
0.05359999999999998
Precisión por categoría:
No Si
0 0.726744 0.981447
SIGMOID
instancia_svm = SVC(kernel="sigmoid", C = 15)
analisis_Credito = Analisis_Predictivo(datos,predecir= "BuenPagador",modelo=instancia_svm, train_size= 0.75)
resultados = analisis_Credito.fit_predict_resultados()
Matriz de Confusión:
[[ 23 145]
[133 949]]
Precisión Global:
0.7776
Error Global:
0.22240000000000004
Precisión por categoría:
No Si
0 0.136905 0.877079
POLY
instancia_svm = SVC(kernel="poly", degree = 4, C = 15)
analisis_Credito = Analisis_Predictivo(datos,predecir= "BuenPagador",modelo=instancia_svm, train_size= 0.75)
resultados = analisis_Credito.fit_predict_resultados()
Matriz de Confusión:
[[ 107 88]
[ 12 1043]]
Precisión Global:
0.92
Error Global:
0.07999999999999996
Precisión por categoría:
No Si
0 0.548718 0.988626
datos = pd.read_csv('../datos/SAheart.csv', delimiter = ';', decimal = ".")
print("SAheart shape: ", datos.shape, "\n")SAheart shape: (462, 10)
print(datos.info(), "\n")<class 'pandas.core.frame.DataFrame'>
RangeIndex: 462 entries, 0 to 461
Data columns (total 10 columns):
# Column Non-Null Count Dtype
--- ------ -------------- -----
0 sbp 462 non-null int64
1 tobacco 462 non-null float64
2 ldl 462 non-null float64
3 adiposity 462 non-null float64
4 famhist 462 non-null object
5 typea 462 non-null int64
6 obesity 462 non-null float64
7 alcohol 462 non-null float64
8 age 462 non-null int64
9 chd 462 non-null object
dtypes: float64(5), int64(3), object(2)
memory usage: 36.2+ KB
None
datos.head() sbp tobacco ldl adiposity famhist typea obesity alcohol age chd
0 160 12.00 5.73 23.11 Present 49 25.30 97.20 52 Si
1 144 0.01 4.41 28.61 Absent 55 28.87 2.06 63 Si
2 118 0.08 3.48 32.28 Present 52 29.14 3.81 46 No
3 170 7.50 6.41 38.03 Present 51 31.99 24.26 58 Si
4 134 13.60 3.50 27.78 Present 60 25.99 57.34 49 Si
analisis_SAheart = Analisis_Predictivo(datos, predecir="chd")
analisis_SAheart.distribucion_variable_predecir()
plt.show()Preparación de datos
# Convierte las variables de object a categórica
datos['famhist'] = datos['famhist'].astype('category')
#Convertimos a Dummy algunas de las variables predictoras
datos = pd.get_dummies(datos,columns=["famhist"])
datos.head() sbp tobacco ldl adiposity ... age chd famhist_Absent famhist_Present
0 160 12.00 5.73 23.11 ... 52 Si 0 1
1 144 0.01 4.41 28.61 ... 63 Si 1 0
2 118 0.08 3.48 32.28 ... 46 No 0 1
3 170 7.50 6.41 38.03 ... 58 Si 0 1
4 134 13.60 3.50 27.78 ... 49 Si 0 1
[5 rows x 11 columns]
Construcción y Evaluación del modelo
instancia_svm = SVC(kernel="rbf", C = 10)
analisis_SAHeart = Analisis_Predictivo(datos,predecir= "chd",modelo=instancia_svm, train_size= 0.8)
resultados = analisis_SAHeart.fit_predict_resultados()
Matriz de Confusión:
[[51 9]
[18 15]]
Precisión Global:
0.7096774193548387
Error Global:
0.29032258064516125
Precisión por categoría:
No Si
0 0.85 0.454545
Construcción y Evaluación del modelo
POLY
instancia_svm = SVC(kernel="poly", degree = 5, C = 10)
analisis_SAHeart = Analisis_Predictivo(datos,predecir= "chd",modelo=instancia_svm, train_size= 0.8)
resultados = analisis_SAHeart.fit_predict_resultados()
Matriz de Confusión:
[[55 4]
[21 13]]
Precisión Global:
0.7311827956989247
Error Global:
0.26881720430107525
Precisión por categoría:
No Si
0 0.932203 0.382353
LINEAR
instancia_svm = SVC(kernel="linear", C = 10)
analisis_SAHeart = Analisis_Predictivo(datos,predecir= "chd",modelo=instancia_svm, train_size= 0.8)
resultados = analisis_SAHeart.fit_predict_resultados()
Matriz de Confusión:
[[47 11]
[21 14]]
Precisión Global:
0.6559139784946236
Error Global:
0.34408602150537637
Precisión por categoría:
No Si
0 0.810345 0.4
SIGMOID
instancia_svm = SVC(kernel="sigmoid", C = 10)
analisis_SAHeart = Analisis_Predictivo(datos,predecir= "chd",modelo=instancia_svm, train_size= 0.8)
resultados = analisis_SAHeart.fit_predict_resultados()
Matriz de Confusión:
[[48 15]
[13 17]]
Precisión Global:
0.6989247311827957
Error Global:
0.30107526881720426
Precisión por categoría:
No Si
0 0.761905 0.566667
datos = pd.DataFrame({"a": [8, 7, 6.5, 5.5, 9, 7], "b": [10, 8, 9, 8.5, 7.8, 9],
"c": [7, 6, 7, 5, 4.5, 6.5], "d": [8, 7, 6.7, 7.8, 9, 8]})
datos a b c d
0 8.0 10.0 7.0 8.0
1 7.0 8.0 6.0 7.0
2 6.5 9.0 7.0 6.7
3 5.5 8.5 5.0 7.8
4 9.0 7.8 4.5 9.0
5 7.0 9.0 6.5 8.0
Obtenemos medias y desviaciones estándar
#Desviación estándar poblacional
desviaciones = datos.std(ddof= 0)
print("Desviaciones estándar\n", desviaciones, "\n")
#MediasDesviaciones estándar
a 1.105542
b 0.731247
c 0.957427
d 0.747774
dtype: float64
medias = datos.mean()
print("Medias\n", medias, "\n")Medias
a 7.166667
b 8.716667
c 6.000000
d 7.750000
dtype: float64
datos2 = datos.copy()for i in range(datos.shape[1]):
datos2.iloc[:,i] = (datos2.iloc[:,i] - medias[i]) / desviaciones[i]
datos2 a b c d
0 0.753778 1.754993 1.044466 0.334325
1 -0.150756 -0.980061 0.000000 -1.002976
2 -0.603023 0.387466 1.044466 -1.404167
3 -1.507557 -0.296297 -1.044466 0.066865
4 1.658312 -1.253566 -1.566699 1.671627
5 -0.150756 0.387466 0.522233 0.334325
Estandarizar datos nuevos es muy similar a la forma en que se realiza manualmente sin utilizar bibliotecas, la única diferencia consiste en utilizar los valores como la media y desviación estándar obtenidos al momento de estandarizar los datos con los que se entrenó el modelo.
datos_nuevos = pd.DataFrame({"a": [9, 8, 6], "b": [9, 7.5, 8], "c": [6.5, 7, 6], "d": [9, 8, 7]})
datos_nuevos a b c d
0 9 9.0 6.5 9
1 8 7.5 7.0 8
2 6 8.0 6.0 7
datos_nuevos2 = datos_nuevos.copy()
for i in range(datos.shape[1]):
datos_nuevos2.iloc[:,i] = (datos_nuevos2.iloc[:,i] - medias[i]) / desviaciones[i]
datos_nuevos2 a b c d
0 1.658312 0.387466 0.522233 1.671627
1 0.753778 -1.663824 1.044466 0.334325
2 -1.055290 -0.980061 0.000000 -1.002976
datos3 = datos.copy()estandarizador = StandardScaler()
datos3 = pd.DataFrame(estandarizador.fit_transform(datos3), columns= datos.columns)
datos3 a b c d
0 0.753778 1.754993 1.044466 0.334325
1 -0.150756 -0.980061 0.000000 -1.002976
2 -0.603023 0.387466 1.044466 -1.404167
3 -1.507557 -0.296297 -1.044466 0.066865
4 1.658312 -1.253566 -1.566699 1.671627
5 -0.150756 0.387466 0.522233 0.334325
Simplemente debemos utilizar la instancia que creamos para estandarizar los datos con los que se entrenó el modelo. Este objeto guarda por dentro los valores de medias y desviaciones estándar.
datos_nuevos3 = datos_nuevos.copy()
#No debemos utilizar fit
datos_nuevos3 = pd.DataFrame(estandarizador.transform(datos_nuevos3), columns= datos_nuevos.columns)
datos_nuevos3 a b c d
0 1.658312 0.387466 0.522233 1.671627
1 0.753778 -1.663824 1.044466 0.334325
2 -1.055290 -0.980061 0.000000 -1.002976
Suponga que se tiene la siguiente tabla de datos:
| X | Y | Z | Clase | |
|---|---|---|---|---|
| 1 | 0 | 1 | Rojo | |
| 1 | 0 | 2 | Rojo | |
| 1 | 1 | 2 | Rojo | |
| 3 | 1 | 4 | Rojo | |
| 1 | 1 | 3 | Rojo | |
| 3 | 2 | 3 | Azul | |
| 1 | 2 | 1 | Azul | |
| 3 | 2 | 1 | Azul | |
| 1 | 1 | 0 | Azul |
d = {'X': [1, 1, 1, 3, 1, 3, 1, 3, 1], 'Y': [0, 0, 1, 1, 1, 2, 2, 2, 1],
'Z': [1, 2, 2, 4, 3, 3, 1, 1, 0],
'Clase': ['Rojo', 'Rojo', 'Rojo', 'Rojo', 'Rojo', 'Azul', 'Azul', 'Azul', 'Azul']}
df = pd.DataFrame(data = d)
df X Y Z Clase
0 1 0 1 Rojo
1 1 0 2 Rojo
2 1 1 2 Rojo
3 3 1 4 Rojo
4 1 1 3 Rojo
5 3 2 3 Azul
6 1 2 1 Azul
7 3 2 1 Azul
8 1 1 0 Azul
Graficamos los puntos
import plotly.graph_objs as go
import plotly.express as px
fig = px.scatter_3d(df, x='X', y='Y', z='Z',
color='Clase',color_discrete_map = {"Rojo": "red", "Azul": "blue"})
fig.show()def ecuacion_hiperplano(P, Q, R):
P = np.array(P)
Q = np.array(Q)
R = np.array(R)
PQ = Q - P
PR = R - P
T = np.cross(PQ, PR)
x = np.array([1, -P[0]]) * T[0]
y = np.array([1, -P[1]]) * T[1]
z = np.array([1, -P[2]]) * T[2]
n = x[1] + y[1] + z[1]
x = x[0]
y = y[0]
z = z[0]
print(str(x) + 'x' + ('+' if y > 0 else '') + str(y) + 'y' + ('+' if z > 0 else '') + str(z) + 'z' + ' = ' + str(-n))Vectores de Soporte
Clase Roja
# Los siguientes 3 puntos corresponden a los puntos de soporte, encontrados en el gráfico.
P = [1, 1, 2]
Q = [1, 0, 1]
R = [3, 1, 4]
ecuacion_hiperplano(P,Q,R)-2x-2y+2z = 0
Dividiendo entre 2 en ambos lados de la igualdad tenemos:
\[-x-y+z = 0\]
Luego tenemos que:
\[z=x+y\]
Clase Azul
# Los siguientes 3 puntos corresponden a los puntos de soporte, encontrados en el gráfico.
P = [1, 2, 1]
Q = [1, 1, 0]
R = [3, 2, 3]
ecuacion_hiperplano(P, Q, R)-2x-2y+2z = -4
Dividiendo entre 2 en ambos lados de la igualdad tenemos:
\[-x-y+z = -2\]
Igualamos a 0:
\[-x-y+z+2 = 0\]
Luego tenemos que:
\[z=x+y−2\]Ecuación del hiperplano óptimo de separación
\[-x-y+z+1=0\]
Luego tenemos que:
\[z = x+y-1\]
Graficamos
fig = px.scatter_3d(df, x='X', y='Y', z='Z',
color='Clase',color_discrete_map = {"Rojo": "red", "Azul": "blue"})
x, y = np.meshgrid(range(5), range(5))
z_rojo = x + y
z_azul = x + y - 2
z_optimo = x + y - 1
fig.add_trace(go.Surface(
x = x,
y = y,
z = z_rojo,
opacity = .7, showscale = False,
colorscale = np.repeat('red', x.size, axis = 0)
)).add_trace(go.Surface(
x = x,
y = y,
z = z_azul,
opacity = .7, showscale = False,
colorscale = np.repeat('blue', x.size, axis = 0)
)).add_trace(go.Surface(
x = x,
y = y,
z = z_optimo,
opacity = .7, showscale = False,
colorscale = np.repeat('green', x.size, axis = 0)
))La ecuación \(−𝑥−𝑦+𝑧+0.5=0\) corresponde a un hiperplano de separación pero no el óptimo.
fig = px.scatter_3d(df, x='X', y='Y', z='Z',
color='Clase',color_discrete_map = {"Rojo": "red", "Azul": "blue"})
x, y = np.meshgrid(range(5), range(5))
z_rojo = x + y
z_azul = x + y - 2
#Hiperplano no optimo
z_optimo = x + y - 0.5
fig.add_trace(go.Surface(
x = x,
y = y,
z = z_rojo,
opacity = .7, showscale = False,
colorscale = np.repeat('red', x.size, axis = 0)
)).add_trace(go.Surface(
x = x,
y = y,
z = z_azul,
opacity = .7, showscale = False,
colorscale = np.repeat('blue', x.size, axis = 0)
)).add_trace(go.Surface(
x = x,
y = y,
z = z_optimo,
opacity = .7, showscale = False,
colorscale = np.repeat('green', x.size, axis = 0)
))Podemos ver como ahora el hiperplano de separación se encuentra más cerca del vector de soporte para la clase Rojo, ya no está exactamente en el medio, por lo que no maximiza el margen y no es óptimo
Observación adicional de manera que las dos clases ya no sean separables por un hiperplano.
#Agregamos un individuo nuevo
#Agregamos el individuo (x = 1, y = 0, z = 4)
d = {'X': [1, 1, 1, 3, 1, 3, 1, 3, 1, 1], 'Y': [0, 0, 1, 1, 1, 2, 2, 2, 1, 0],
'Z': [1, 2, 2, 4, 3, 3, 1, 1, 0, 4],
'Clase': ['Rojo', 'Rojo', 'Rojo', 'Rojo', 'Rojo', 'Azul', 'Azul', 'Azul', 'Azul','Azul']}
df = pd.DataFrame(data = d)
df X Y Z Clase
0 1 0 1 Rojo
1 1 0 2 Rojo
2 1 1 2 Rojo
3 3 1 4 Rojo
4 1 1 3 Rojo
5 3 2 3 Azul
6 1 2 1 Azul
7 3 2 1 Azul
8 1 1 0 Azul
9 1 0 4 Azul
fig = px.scatter_3d(df, x='X', y='Y', z='Z',
color='Clase',color_discrete_map = {"Rojo": "red", "Azul": "blue"})
x, y = np.meshgrid(range(5), range(5))
z_rojo = x + y
z_azul = x + y - 2
z_optimo = x + y - 1
fig.add_trace(go.Surface(
x = x,
y = y,
z = z_rojo,
opacity = .7, showscale = False,
colorscale = np.repeat('red', x.size, axis = 0)
)).add_trace(go.Surface(
x = x,
y = y,
z = z_azul,
opacity = .7, showscale = False,
colorscale = np.repeat('blue', x.size, axis = 0)
)).add_trace(go.Surface(
x = x,
y = y,
z = z_optimo,
opacity = .7, showscale = False,
colorscale = np.repeat('green', x.size, axis = 0)
))